import React, { useEffect, useRef, useState } from 'react'
import { InboxOutlined, CaretRightOutlined, CheckOutlined } from '@ant-design/icons'
import { message, Button, Progress } from 'antd'
import { useApi } from '../../api/index'
import SparkMD5 from 'spark-md5'

//文件切片
const createChunk = (file, chunkSize) => {
  const results = []
  for (let i = 0; i < file.size; i += chunkSize) {
    results.push(file.slice(i, i + chunkSize))
  }
  return results
}

//哈希命名
const hash = chunks => {
  return new Promise(resolve => {
    const spark = new SparkMD5.ArrayBuffer()
    const readFile = async i => {
      //读取完成,返回结果
      if (i >= chunks.length) {
        resolve(spark.end())
        return
      }

      const blob = chunks[i]
      const reader = new FileReader()
      reader.readAsArrayBuffer(blob)
      reader.onload = e => {
        const bytes = e.target.result
        spark.append(bytes)
        readFile(i + 1)
      }
    }
    readFile(0)
  })
}

// const workTask = async ({ file, chunkSize }) => {
//   //文件切片
//   const createChunk = (file, chunkSize) => {
//     const results = []
//     for (let i = 0; i < file.size; i += chunkSize) {
//       results.push(file.slice(i, i + chunkSize))
//     }
//     return results
//   }

//   //哈希命名
//   const hash = chunks => {
//     return new Promise(resolve => {
//       const spark = new SparkMD5()
//       const readFile = async i => {
//         //读取完成,返回结果
//         if (i >= chunks.length) {
//           resolve(spark.end())
//           return
//         }

//         const blob = chunks[i]
//         const reader = new FileReader()
//         reader.onload = e => {
//           //读取到的字节数
//           const bytes = e.target.result
//           spark.append(bytes)
//           readFile(i + 1)
//         }
//         reader.readAsArrayBuffer(blob)
//       }
//       readFile(0)
//     })
//   }
//   //文件切片
//   const chunks = createChunk(file, chunkSize)
//   //计算hash
//   const fileHash = await hash(chunks)

//   return {
//     chunks,
//     fileHash
//   }
// }

//上传文件组件
function CommonUpload({ uploaded }) {
  //请求接口
  const { uploads, mergeChunk, verifyFile } = useApi()

  //被上传的文件对象
  const uploadFile = useRef(null)

  //网络中断器
  const controller = useRef(null)

  //上传状态,0表示未上传文件，-1表示断网或者暂停上传，1表示正在上传文件，2表示上传成功
  const [uploadStatus, setUploadStatus] = useState(0)
  const status = useRef(0)

  //文件上传进度
  const [successTask, setSuccessTask] = useState(0)
  let taskLength = useRef(0)
  const [uploadProgress, setUploadProgress] = useState(0)

  //拖拽时的背景色
  const [bgColor, setBgColor] = useState('rgba(0,0,0,0.06)')

  //计算进度条
  useEffect(() => {
    let progress =
      taskLength.current == 0 ? 0 : +((successTask * 100) / taskLength.current).toFixed(2)
    setUploadProgress(progress)
  }, [successTask])

  //上传按钮状态,true表示上传，false表示停止
  const [buttonStatus, setButtonStatus] = useState(true)

  //监听网络掉线
  useEffect(() => {
    window.addEventListener('offline', () => {
      if (status.current == 1) {
        setUploadStatus(-1)
        status.current = -1
        setButtonStatus(false)
        message.error('网络异常，上传失败')
      }
    })

    return () => {
      window.removeEventListener('offline', () => {
        if (status.current == 1) {
          setUploadStatus(-1)
          status.current = -1
          setButtonStatus(false)
          message.error('网络异常，上传失败')
        }
      })
    }
  }, [])

  //控制请求并发
  const controlRequest = (taskPool, max) => {
    return new Promise(resolve => {
      if (taskPool.length === 0) {
        resolve([])
        return
      }
      //结果存放处
      const results = []
      let index = 0

      //已完成的任务数
      let count = 0

      //递归
      const toRequest = async () => {
        //任务已全部填加进队列中，结束递归
        if (index == taskPool.length) return
        //网络异常，或者点击暂停
        if (status.current == -1) {
          //中断之前的请求
          controller.current.abort()
          resolve(results)
          return
        }
        const i = index
        const task = taskPool[index]
        index++
        try {
          let res = await task()

          //暂停上传时，可能还有正在上传的任务返回结果导致进度条异常
          //这些正在上传的
          if (status.current == -1) {
            return
          }

          results[i] = res
          //已完成任务数加一
          setSuccessTask(successTask => successTask + 1)
          count++

          //任务已全部完成
          if (count == taskPool.length) {
            resolve(results)
            return
          }
          //否则继续递归填加任务
          toRequest()
        } catch (error) {
          if (error.message == 'canceled') {
            console.log('请求中断')
          } else {
            console.log('网络异常', error)
          }
          setUploadStatus(-1)
          status.current = -1
          setButtonStatus(false)
        }
      }

      //如果网络断开或者暂停,从新上次的进度就是taskLength.current - taskPool.length开始
      if (taskLength.current != 0) {
        setSuccessTask(taskLength.current - taskPool.length)
      } else {
        taskLength.current = taskPool.length
      }

      //初次填加任务
      const time = Math.min(max, taskPool.length)
      for (let i = 0; i < time; i++) {
        toRequest()
      }
    })
  }

  //上传文件分片,并请求合并文件，过滤已上传过的文件分片，上传成功后，发送请求合并文件
  const uploadChunks = async (chunks, fileHash, fileName, existChunks) => {
    try {
      //保存请求中断控制器
      controller.current = new AbortController()

      //组装请求参数,生成请求队列
      const taskPool = chunks
        .map((chunk, index) => {
          const form = {
            fileHash: fileHash,
            chunkHash: fileHash + '-' + index,
            chunk
          }
          return form
        })
        //过滤已上传过的文件分片
        .filter(form => {
          return !existChunks.includes(form.chunkHash)
        })
        .map(form => {
          const formData = new FormData()
          formData.append('fileHash', form.fileHash)
          formData.append('chunkHash', form.chunkHash)
          formData.append('chunk', form.chunk)

          return async () => {
            return await uploads({
              formData,
              signal: controller.current.signal
            })
          }
        })

      //上传文件
      await controlRequest(taskPool, 6)

      //上传成功后，发送请求合并文件
      if (status.current !== -1) {
        const { url } = await mergeChunk({
          data: {
            fileHash,
            fileName
          },
          signal: controller.current.signal
        })
        //上传成功的回调
        message.success({
          content: '上传成功',
          duration: 2
        })

        uploadSuccess(url)
      }
    } catch (error) {
      message.error('异常')
      console.log('err', error)
    }
  }

  //文件上传
  const handlerUpload = async (e, storeFile) => {
    try {
      let target = null
      //第一次上传
      if (storeFile == null) {
        target = e.target.files
      } else {
        target = storeFile
      }

      uploadFile.current = target

      const length = target.length
      const file = target[length - 1]
      const fileName = file.name

      // 正在上传文件
      setUploadStatus(1)
      status.current = 1

      //文件切片
      const chunks = createChunk(file, 1024 * 1024)

      //计算hash
      const fileHash = await hash(chunks)

      //文件秒传，文件校验
      const verifyResult = await verifyFile({
        fileHash,
        fileName
      })

      const { existFile, existChunks, url } = verifyResult

      //文件已上传过
      if (existFile) {
        message.success('上传成功')
        uploadSuccess(url)
        return
      }

      //依次上传文件分片
      uploadChunks(chunks, fileHash, fileName, existChunks)
    } catch (error) {
      message.error('异常')
      console.log('err', error)
    }
  }

  //上传成功要做的事情
  const uploadSuccess = url => {
    //上传成功
    setUploadProgress(100)
    setUploadStatus(2)
    status.current = 2

    //触发父组件保存
    uploaded(url)
  }

  //点击按钮，暂停或者继续上传
  const stopUpload = () => {
    if (status.current == 2) {
      return
    }
    //上传变暂停
    if (buttonStatus) {
      //中断之前的网络请求
      console.log('中断', controller.current)

      controller.current.abort()
      //修改状态
      setButtonStatus(false)
      setUploadStatus(-1)
      status.current = -1
    } else {
      //重新上传
      handlerUpload(null, uploadFile.current)
      setUploadStatus(1)
      status.current = 1
      setButtonStatus(true)
    }
  }

  //自定义进度条内容
  const format = percent => {
    if (status.current == -1) {
      return (
        <CaretRightOutlined
          style={{
            fontSize: '1rem',
            marginLeft: '.2rem',
            color: '#1677ff',
            transition: 'all 300ms'
          }}
          className="upload"
        ></CaretRightOutlined>
      )
    } else if (status.current == 2) {
      return <CheckOutlined style={{ color: '#52c41a', fontSize: '1rem' }}>Success</CheckOutlined>
    } else {
      return <span style={{ color: '#1677ff' }}>{percent}%</span>
    }
  }

  //拖拽上传
  const handlerDragEnter = e => {
    e.preventDefault()
    if (bgColor == 'rgba(0,0,0,0.06)') {
      setBgColor('#4096ff')
    }
  }
  const handlerDragLeave = e => {
    e.preventDefault()
    if (e.target.tagName == 'LABEL') {
      setBgColor('')
    }
  }
  const handlerDropOver = e => {
    e.preventDefault()
    setBgColor('#4096ff')
  }
  const handlerDrop = e => {
    e.preventDefault()
    setBgColor('rgba(0,0,0,0.06)')
    // console.log('dra', uploadFile)
    if (uploadFile.current) {
      message.warning('已上传过文件了')
      return
    }
    // console.log('11', e.dataTransfer.files)

    handlerUpload(null, e.dataTransfer.files)
  }

  return (
    <>
      {/*  */}

      <label
        for="file"
        onDragEnter={handlerDragEnter}
        onDragLeave={handlerDragLeave}
        onDragOver={handlerDropOver}
        onDrop={handlerDrop}
        style={{ backgroundColor: `${bgColor}` }}
        className=" flex flex-col justify-center items-center w-[100%] h-[100%] outline-none rounded-[.1rem]   cursor-pointer  text-center  border-[#d9d9d9] border-[.0125rem] border-dashed  transition-[border-color] duration-[0.3s] hover:border-[#4096ff]"
      >
        <div style={{ display: uploadStatus !== 0 ? 'none' : 'block' }}>
          <p className="ant-upload-drag-icon w-[19.075rem] h-[.6rem] mb-[.2rem] ">
            <InboxOutlined className="text-[.6rem] text-[#1677ff]" />
          </p>
          <p className="ant-upload-text mb-[.2rem] text-[.2rem] text-[rgba(1,1,1,0.8)]">
            点击选择或拖拽文件到区域内上传
          </p>
          <p className="ant-upload-hint text-[.175rem] text-[rgba(1,1,1,0.4)]">仅支持单次上传</p>
        </div>
        <Progress
          type="circle"
          percent={uploadProgress}
          format={format}
          onClick={stopUpload}
          style={{ display: uploadStatus === 0 ? 'none' : 'block', fontSize: '1rem' }}
        />
      </label>
      <input
        disabled={uploadStatus != 0}
        type="file"
        id="file"
        onChange={e => handlerUpload(e, uploadFile.current)}
        className="hidden"
      ></input>
    </>
  )
}

export default CommonUpload
